ARTIFICIAL INTELLIGENCE ALGORITHMS¶

Practical Lab¶

#1¶


In [135]:
import numpy as np
import plotly as plotly

plotly.offline.init_notebook_mode()  # Required to show maps in HTML files

import plotly.express as px  # For graphs

Part A¶

  1. Create an array that starts from the integer 1, ends at 20, incremented by 3.
In [136]:
np.arange(1, 21, 3)
Out[136]:
array([ 1,  4,  7, 10, 13, 16, 19])
  1. Create a new array of shape 3 with random numbers between 0 and 1.
In [137]:
# random.rand() function can be used to generate random numbers in between interval [0, 1]
np.random.rand(1, 3)
Out[137]:
array([[0.98730274, 0.56516493, 0.38614071]])
  1. Create a 2D array [[10,20,45], [30,12,16], [42,17,56]] and perform the following operations:

    A. Slice the 2D array to get the first two rows.
    B. Slice the 2D array to get the last two rows.

In [138]:
q4__arr = np.array([[10, 20, 45], [30, 12, 16], [42, 17, 56]])

# Selects items starting from 1 to 2 rows and all columns
q4__sliceA = q4__arr[:2,]

# Selects items starting from last-2 rows to last and all columns
q4__sliceB = q4__arr[-2:,]

print(f"A: First 2 rows \n{q4__sliceA}")
print(f"\nB: Last 2 rows \n{q4__sliceB}")
A: First 2 rows 
[[10 20 45]
 [30 12 16]]

B: Last 2 rows 
[[30 12 16]
 [42 17 56]]
  1. Create two 2x2 arrays and demonstrate how you can stack the elements vertically, horizontally, and split the arrays into smaller arrays.
In [139]:
# Create 2 dummy source arrays
q5__arr1 = np.random.rand(2, 2)
q5__arr2 = np.random.rand(2, 2)
In [140]:
# Stacked vertically
q5__arrV = np.vstack((q5__arr1, q5__arr2))
q5__arrV
Out[140]:
array([[0.20165831, 0.70815047],
       [0.24554309, 0.30539436],
       [0.33261953, 0.57778699],
       [0.67810139, 0.58209529]])
In [141]:
# Stacked horizontally
q5__arrH = np.hstack((q5__arr1, q5__arr2))
q5__arrH
Out[141]:
array([[0.20165831, 0.70815047, 0.33261953, 0.57778699],
       [0.24554309, 0.30539436, 0.67810139, 0.58209529]])
In [142]:
# Split to 2 vertically
np.vsplit(q5__arrV, 2)
Out[142]:
[array([[0.20165831, 0.70815047],
        [0.24554309, 0.30539436]]),
 array([[0.33261953, 0.57778699],
        [0.67810139, 0.58209529]])]
In [143]:
# Split to 2 horizontally
np.hsplit(q5__arrH, 2)
Out[143]:
[array([[0.20165831, 0.70815047],
        [0.24554309, 0.30539436]]),
 array([[0.33261953, 0.57778699],
        [0.67810139, 0.58209529]])]
  1. Create two matrices X= ([[5, 7, 2], [4, 5, 6], [7, 4 ,2]]) Y= ([[4, 2], [6, 2], [4, 2]]), Is it possible to multiply these matrices? Demonstrate the case when it is not possible to.
In [144]:
q6__X = np.array([[5, 7, 2], [4, 5, 6], [7, 4, 2]])
q6__Y = np.array([[4, 2], [6, 2], [4, 2]])

print(f"Shape of X: {q6__X.shape}")
print(f"Shape of Y: {q6__Y.shape}")
Shape of X: (3, 3)
Shape of Y: (3, 2)

For the matrix multiplication to be possible, the number of columns in first matrix should be equal to number of rows in second matrix. This will produce a resultant matrix of number of rows equal to that of first matrix and number of columns equal to that of second matrix.

In above example X.Y is possible because the number of columns in X is same as number of rows in Y. However, Y.X is not allowed since the condition doesn't hold true in this case.

In [145]:
np.matmul(q6__X, q6__Y)
Out[145]:
array([[70, 28],
       [70, 30],
       [60, 26]])
  1. Create two arrays, x = ([2, -1, -8]) y = ([3, 1, -2]), Find the Shape, Number of dimensions of vector x. Reshape the vector x to a matrix of size (3,1) and determine the number of dimensions after reshaping y to a matrix of (3,1).
In [146]:
q7__x = np.array([[2, -1, 8]])
q7__y = np.array([[3, 1, -2]])

print("BEFORE RESHAPE - ")
print(f"'x'\n \tshape: {q7__x.shape} \n\tdimensions: {q7__x.ndim}")
print(f"'y'\n \tshape: {q7__y.shape} \n\tdimensions: {q7__y.ndim}")
BEFORE RESHAPE - 
'x'
 	shape: (1, 3) 
	dimensions: 2
'y'
 	shape: (1, 3) 
	dimensions: 2
In [147]:
q7__x = np.reshape(q7__x, (3, -1))
q7__y = np.reshape(q7__y, (3, -1))

print("AFTER RESHAPE - ")
print(f"'x'\n \tshape: {q7__x.shape} \n\tdimensions: {q7__x.ndim}")
print(f"'y'\n \tshape: {q7__y.shape} \n\tdimensions: {q7__y.ndim}")
AFTER RESHAPE - 
'x'
 	shape: (3, 1) 
	dimensions: 2
'y'
 	shape: (3, 1) 
	dimensions: 2
  1. How does broadcasting work? Demonstrate the subtraction, multiplication by considering a 3 x 3 matrix.

"Broadcasting" is a method in numpy which enables elementwise operation on arrays having different shapes but are comparitible with the rules of broadcasting. It works by repeating or "stretching" the elements in the array having smaller dimension to match dimension array.

In [148]:
# Larger dimension array of shape (3x3)
q8__arr1 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# Smaller dimension array of shape (3x1)
q8__arr2 = np.array([1, 2, 3])
In [149]:
# Example 1: Substraction
q8__arr1 - q8__arr2
Out[149]:
array([[0, 0, 0],
       [3, 3, 3],
       [6, 6, 6]])
In [150]:
# Example 2: Multiplication
q8__arr1 * q8__arr2
Out[150]:
array([[ 1,  4,  9],
       [ 4, 10, 18],
       [ 7, 16, 27]])

In both operations, the array with lower dimension (3x1) is expanded to match dimension of larger dimension array(3x3) by repeating values in it's first axis before elementwise operation is perfomed in each axis. The result of such operations will always produce array of dimension matching the largest dimension in the operand.

  1. Add Markdown text, with a headline, that provides a very brief overview of the graphs (e.g., one sentence for each).

Types of Graphs¶

  • Bar Graph¶
    A graph representing categorical data with rectangular bars of varying heights.
In [151]:
q9__data1 = px.data.gapminder().query("country == 'Canada'")
q9__figBar = px.bar(
    q9__data1,
    x="year",
    y="pop",
    title="Population Growth",
    labels={"pop": "Population", "year": "Year"},
)
q9__figBar.show()
  • Line Plot¶
    Graph showing the trend of a variable over a continuous range of values.
In [152]:
q9__figLine = px.line(
    q9__data1,
    x="year",
    y="pop",
    title="Population Growth",
    labels={"pop": "Population", "year": "Year"},
)
q9__figLine.show()
  • ScatterPlot¶
    Graph displaying individual data points as markers on a coordinate grid
In [153]:
q9__figScatter = px.scatter(
    q9__data1,
    x="year",
    y="pop",
    title="Population Growth",
    labels={"pop": "Population", "year": "Year"},
)
q9__figScatter.show()
  • Pie Chart¶
    Circular chart divided into sectors, representing the ratio of proportion categories in a dataset
In [154]:
q9__data2 = px.data.gapminder().query("year == 2002").head(10)
# Comparison of population of 10 countries in the year 2002
q9__figPie = px.pie(q9__data2, values="pop", names="country")
q9__figPie.show()

Part B¶

  1. Solve the following two system of linear equations using matrices (find the values of x1 and x2) and determine the number of solutions using the functions.
    1. 2x1+3x2-4x3=6,x1-4x2=8 2. 3y1-4y2+5y3=10,-y1+2y2-4y3=8

In both of the system of equations above, we have 3 unknown variables [x1, x2, x3] and [y1, y2, 3]. But only 2 equations are given. We need one more equation to solve the system of equations. Hence this is invalid.